import java.util.*;
import javax.crypto.*;

public class PCBC extends Mode
{
	public PCBC() {}
	
	public byte[] Encrypt(SecretKey key1, SecretKey key2, byte[] IV, byte[] plainText) throws Exception
	{
		if (IV.length != 8) 
			throw new Exception("PCBC Encryption: Initalization Vector size =! 8");
	
		int textLength = plainText.length;
		int r = textLength % 8;
		
		int cipherLength;
		if (r == 0)
			cipherLength = textLength;
		else
			cipherLength = textLength + (8 - r);
		
		cipherLength = cipherLength + 8;
		plainText = Arrays.copyOf(plainText, cipherLength);
		
		byte[] cipherText = new byte[cipherLength];
		byte[] currentBlock = new byte[8];
		byte[] textXorCipher = new byte[8];
		
		TripleDES des = new TripleDES();
		
		for (int i = 0; i < cipherLength; i += 8)
		{
			if (i == 0)
				currentBlock = XOR(Arrays.copyOfRange(plainText, i, i + 8), IV);
			else
				currentBlock = XOR(Arrays.copyOfRange(plainText, i, i + 8), textXorCipher);
							
			currentBlock = des.Encrypt(key1, key2, currentBlock);
			ReplaceBlock(cipherText, currentBlock, i);
			
			textXorCipher = XOR(Arrays.copyOfRange(plainText, i, i + 8), currentBlock);
		}
		
		return cipherText;
	}	
	
	public byte[] Decrypt(byte[] key, byte[] IV, byte[] cipherText, boolean[] macIsValid) throws Exception
	{
		byte[] plainText = Decrypt(key, IV, cipherText);
		
		byte[] mac = Arrays.copyOfRange(plainText, plainText.length - 8, plainText.length);
		//make sure mac equals 8 bytes of zeros
		macIsValid[0] = true;
		for (int i = 0; i < mac.length; i++)
		{
			if (mac[i] != 0)
			{
				macIsValid[0] = false;
				break;
			}
		}
		
		return Arrays.copyOfRange(plainText, 0, plainText.length - 8);
	}
	
	public byte[] Decrypt(SecretKey key1, SecretKey key2, byte[] IV, byte[] cipherText) throws Exception
	{
		if (IV.length != 8) 
			throw new Exception("PCBC Decryption: Initalization Vector size =! 8");
	
		int cipherLength = cipherText.length;
		int r = cipherLength % 8;
		
		if (r != 0)
			throw new Exception("PCBC Decryption: cipherText size is not a multiple of 8");
		
		byte[] plainText = new byte[cipherLength];
		byte[] currentBlock = new byte[8];
		byte[] textXorCipher = new byte[8];
		
		TripleDES des = new TripleDES();
		
		for (int i = 0; i < cipherLength; i += 8)
		{
			currentBlock = des.Decrypt(key1, key2, Arrays.copyOfRange(cipherText, i, i + 8));
			if (i == 0)
				currentBlock = XOR(currentBlock, IV);
			else
				currentBlock = XOR(textXorCipher, currentBlock);	
			
			ReplaceBlock(plainText, currentBlock, i);
			textXorCipher = XOR(Arrays.copyOfRange(cipherText, i, i + 8), currentBlock);		
		}
		
		return plainText;
	}
}













